include('shared.lua')

ENT.RenderGroup = RENDERGROUP_BOTH

local SpriteOffset = Vector(0, 0, 32)

local NODE_MODEL = Model("models/Combine_Helicopter/helicopter_bomb01.mdl")
local NODE_MATERIAL = Material( "sprites/light_frame_grip" )

local TRACK_MATERIAL  = Material("sprites/dacre_track")
local LINK_MATERIAL  = Material("sprites/dacre_link")
local BLANK_MATERIAL = Material("cable/white")
local MatSprite = Material("sprites/physg_glow1")
local MAT_HIGHLIGHT = Material("sprites/physg_glow1")


local COLOR_WHITE	= Color(255, 255, 255, 255)

local CurrentHighlightIdx	= -1

local NameRT = nil

function ENT:Initialize()

	self:InitController()

	self.ShouldDraw     = 1
	self.ShouldDrawInfo = false
	
	self.MouseOverIdx = -1

	self.LastDrawCheckTimestamp = 0
	
	self.ZoomTimestamp = 0
	self.LastGuideBeamRenderTimestamp = 0
	
	self:FireShootOff()
	surface.CreateFont( "coolvetica", 24, 500, true, false, "GMDMPickup" )
	
	self.NodeID = -1
	self.Color	= COLOR_WHITE

	self.NameMaterial = BLANK_MATERIAL
	self.TrackName = ""

	//For actor binding to track
	self.NumActors = 0
	self.ActorTable = {}

end

//****************************************************
//*	Enables the client to maintain up to date awareness
//* as to the actors currently attached to itself
function ENT:UpdateActorAttachment()

	local svNumActors = self:GetNWInt("VarNumActors")

	//If our number of actors differs from the server
	//we know we either need to add or remove an actor
	if svNumActors != self.NumActors then
			
		//Try to find out the ID of the actor of interest
		//(ie could be being added or removed)
		local svActorEntID = self:GetNWInt("VarActorEntID")
		if (svActorEntID < 0) then
			self.BaseClass.PrintError(self, "(svActorEntID < 0)")
			return 
		end

		local newActor = ents.GetByIndex(svActorEntID)

		if not self.BaseClass.IsActor(self, newActor) then
			self.BaseClass.PrintError(self, "not self.BaseClass.IsActor(self, newActor)")
			return 
		end

		//Make sure we have a valid actor table before going
		//ahead
		self.ActorTable = self.ActorTable or {}

		if svNumActors > self.NumActors then
		
			self.ActorTable[newActor:EntIndex()] = newActor
		end
		
		if svNumActors < self.NumActors then

			self.ActorTable[newActor:EntIndex()] = nil
			//table.remove(self.ActorTable,newActor:EntIndex())
			//self.ActorTable[newActor:EntIndex()] = nil

		end

		//This needs to be done to stop the entry condition for
		//this code block
		self.NumActors = svNumActors
		
		//Do housecleaning, make sure the ID variable is reset
		//We found an ID but we now need to get the associated
		//entity
		//self:SetNWInt("VarActorEntID", -1)
	end
end

//
//function ENT:UpdateNameLabel()
//	
//	//We only give name labels to the first track node
//	if self.NodeID != 1 then
//		return
//	end
//
//	//We only want to update the RT if nessisary
//	local trackIndex = self.BaseClass.GetTrackIndex(self)
//	if self.TrackName != trackIndex then
//
//		self.TrackName = trackIndex
//
//		//Create a new RT if we dont aleard have one
//		if !self.NameRT then
//			self.NameRT = GetRenderTarget( "NameRT", 128, 32, true )
//		end
//
//		if self.NameRT then
//
//			local prevRT = render.GetRenderTarget();
//		    render.SetRenderTarget( self.NameRT )
//		
//	        render.SetViewPort( 0, 0, 128, 32)
//	        render.Clear( 0, 0, 0,255, true )
//	
//	        cam.Start2D()
//				draw.RoundedBox( 8, 0, 0, 128, 32, Color(18, 22, 19, 250))
//				draw.SimpleTextOutlined( self.TrackName, "GMDMPickup", 64, 0, COLOR_WHITE, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 2, Color(0,0,0,255) )
//	        cam.End2D()
//	
//			render.SetRenderTarget( prevRT )
//			render.SetViewPort( 0, 0, ScrW(), ScrH() )
//		
//			self.NameMaterial:SetMaterialTexture( "$basetexture", self.NameRT )
//		end
//	end
//end

function ENT:Think()

	self.NodeID = self.BaseClass.GetNodeIndex(self)

	self:UpdateActorAttachment()
		
	self.ShouldDrawInfo = (self:GetNWEntity("MasterController"):GetNetworkedEntity("ControllingPlayer") == LocalPlayer())
	self.ShouldDraw     = 1
	
	if (self.ShouldDraw == 0) then return end
	if not self:GetNWBool("IsMasterController") then return end
		
	self:GetPointData()
	
	if #self.CatmullRomController.PointsList >= 4 then
		self.CatmullRomController:CalcEntireSpline()
	else
		self:RemoveGuideGhost()
	end

	self:NextThink(CurTime() + 250)
end

function ENT:Draw()
	if LocalPlayer():GetNWInt("show_objects") == 0 then
		return
	end

	if self:GetNWBool("IsMasterController") then
			self.BaseClass.DrawTrackName(self)
	end

	if self:GetNWBool("IsMapController") then 
		//print("if self:GetNWBool() then --- DRAW")
		return 
	end
	if not self:GetNWEntity("MasterController").RequestGuideBeamDraw then 

		if self:GetNWEntity("MasterController") == nil then
			print("No master controller")
		else
			print(self:GetNWEntity("MasterController"):GetClass())
		end

		print("if not self:GetNWEntity().RequestGuideBeamDraw then --- DRAW")
		return 
	end
				
	if self.ShouldDraw == 0 then 
		//print("if self.ShouldDraw == 0 then --- DRAW")
		return 
	end
	if LocalPlayer():GetNWEntity("UnderControlCatmullRomCamera") == self:GetNWEntity("MasterController") then 
		print("if LocalPlayer():GetNWEntity() == self:GetNWEntity() then --- DRAW")
		return 
	end

	self:DrawNodeLinks()

	 	

	//Draws the interconnection line
	self:RequestGuideBeamDraw(self.NodeID) 
	
	//Draw the floating number
	self.BaseClass.DrawNumber(self, self.NodeID)
	
	//Draw the node
	render.SetMaterial(NODE_MATERIAL)
	render.DrawQuadEasy( self:GetPos(), Vector(0,0,1), 20, 20, Color(255,255,255,255))
	
	if self.BaseClass.GetHighlighting(self) > 0 then
		render.SetMaterial(MAT_HIGHLIGHT)
		render.DrawSprite(self.Entity:GetPos(), 64, 64, Color(255,255,255,255))
	end
	
end

function ENT:DrawTranslucent()

	if LocalPlayer():GetNWInt("show_objects") == 0 then
		return
	end

	if self:GetNWBool("IsMapController") then return end
	if not self:GetNWBool("IsMasterController") then return end
	
	if (not self.ShouldDrawInfo) or (not self.Texture) then return end
	if LocalPlayer():GetNWEntity("UnderControlCatmullRomCamera") == self:GetNWEntity("MasterController") then return end
	
	render.SetMaterial(self.Texture)
	render.DrawSprite(self.Entity:GetPos() + SpriteOffset, 16, 16, color_white)
	self.Entity:DrawModel()

end

//****************************************************
//* This function renders any links that need to be drawn 
//* from/to this node from other actors or nodes in the scene
function ENT:DrawNodeLinks()
	local CTime = CurTime()

	//Look to see if we are in the middle of a user
	//constructing a link from myself to an actor or
	//node. Render this line to provide visual feedback
	local constructDraw, constructEndpoint = self.BaseClass.GetConstructPoint(self)
	if constructDraw == true then
		render.SetMaterial(TRACK_MATERIAL)

		render.StartBeam(2)
		render.AddBeam(self:GetPos(), 5, 5 + CTime, self.Color)
		render.AddBeam(constructEndpoint, 5, CTime, self.Color)
		render.EndBeam()

	end

	//Look to see if there are any links existing between myself
	//and other actors and draw them accordingly
	if self.ActorTable then 
		render.SetMaterial(LINK_MATERIAL)
		for k, v in pairs(self.ActorTable) do
			if self.BaseClass.IsValid(self, v) then
				render.StartBeam(2)
				render.AddBeam(self:GetPos(), 5, 5 + CTime, self.Color)
				render.AddBeam(v:GetPos(), 5, CTime, self.Color)
				render.EndBeam()

			end
		end
	end

end


function ENT:FireShootOff()
	if not (self and self:IsValid()) then return end
	
	self.CurShootOffStart = SysTime()
	self.CurShootOff      = self.CurShootOffStart + .75

end

function ENT:DrawGuideBeam()
	if self:GetNWBool("IsMapController") then return end
	
	if not self:GetNWBool("IsMasterController") then
		if self:GetNWEntity("MasterController"):IsValid() and (LocalPlayer():GetNWEntity("UnderControlCatmullRomCamera") ~= self:GetNWEntity("MasterController")) then
			return self:GetNWEntity("MasterController"):DrawGuideBeam()
		end
		
		return
	end
	
	if #self.CatmullRomController.PointsList < 4 then
		self:RemoveGuideGhost()
		
		return --print("not enough points.", #self.CatmullRomController.PointsList)
	end
	

	if self:GetNWBool("DoHighlight") then
	self:DrawSelected()
	end

	local CTime = UnPredictedCurTime()
	
	if self.LastDrawCheckTimestamp > CTime then return end--print("too soon") end
	
	self.LastDrawCheckTimestamp = CTime
	
	local size = 35 + math.abs(self.CatmullRomController.Perc - .5) * 100
	
	local pos, ang = self:GetGuideCamPosAng()
	
	if not self.GuideCameraGhost then
		self.GuideCameraGhost = ClientsideModel(NODE_MODEL, RENDERGROUP_OPAQUE)
	end
	
	self.GuideCameraGhost:SetModelScale(Vector(1,1,1) * (math.sin(1 - math.abs(self.CatmullRomController.Perc - .5)) * .5 + .6))
	
	self.GuideCameraGhost:SetAngles(ang)
	self.GuideCameraGhost:SetPos(pos)
end

function ENT:RequestGuideBeamDraw(NodeIndex)
	
	if (not self:GetNWBool("IsMasterController")) then
		if self:GetNWEntity("MasterController").RequestGuideBeamDraw then
			return self:GetNWEntity("MasterController"):RequestGuideBeamDraw(NodeIndex)
		end	
		return
	end

	if self.CatmullRomController.CLEntityListCount == 0 then
		return
	end

	render.SetMaterial(TRACK_MATERIAL)

	local CTime = CurTime()

	//This handles clipping so that even if a node is out of screen, the line in between in and a visible node is still drawn
	//TODO: my additions are still not working properly when clipped
	local drawbackbeam    = NodeIndex == 1 or NodeIndex == self.CatmullRomController.CLEntityListCount or ((NodeIndex > 2) and self.CatmullRomController.EntityList[NodeIndex - 1] and (self.CatmullRomController.EntityList[NodeIndex - 1].LastGuideBeamRenderTimestamp < CurTime()))
	local drawforwardbeam = NodeIndex == 1 or NodeIndex == self.CatmullRomController.CLEntityListCount or ((NodeIndex < self.CatmullRomController.CLEntityListCount - 1) and self.CatmullRomController.EntityList[NodeIndex] and (self.CatmullRomController.EntityList[NodeIndex].LastGuideBeamRenderTimestamp < CurTime()))
	
	if drawbackbeam then

		if self.CatmullRomController.EntityList == nil then
			print("CatmullRomController.EntityList = nil")
			return
		elseif #self.CatmullRomController.EntityList < NodeIndex then
			print("CatmullRomController.EntityList < NodeIndex ")
			return
		end

			
		if NodeIndex == 1 then
			if self.CatmullRomController.CLEntityListCount > 1 then
				self.CatmullRomController.EntityList[NodeIndex].LastGuideBeamRenderTimestamp = CTime
				render.StartBeam(2)
				render.AddBeam(self.CatmullRomController.PointsList[NodeIndex], 5, 10 + CTime, self.Color)
				render.AddBeam(self.CatmullRomController.PointsList[NodeIndex + 1], 5, CTime, self.Color)
				render.EndBeam()
			end
		elseif NodeIndex == self.CatmullRomController.CLEntityListCount then
			if self.CatmullRomController.CLEntityListCount > 1 then
				self.CatmullRomController.EntityList[self.CatmullRomController.CLEntityListCount].LastGuideBeamRenderTimestamp = CTime
				render.StartBeam(2)
				render.AddBeam(self.CatmullRomController.PointsList[self.CatmullRomController.CLEntityListCount - 1], 5, 10 + CTime, self.Color)
				render.AddBeam(self.CatmullRomController.PointsList[self.CatmullRomController.CLEntityListCount], 5, CTime, self.Color)
				render.EndBeam()
			end
		else
			self.CatmullRomController.EntityList[NodeIndex - 1].LastGuideBeamRenderTimestamp = CTime
			render.StartBeam(self.CatmullRomController.STEPS + 2)
				ok, err = pcall(self.RenderSubBeams, self, CTime, (NodeIndex - 1))
			render.EndBeam()
		end
	end
	
	if drawforwardbeam then
		if NodeIndex == 1 then
			if self.CatmullRomController.CLEntityListCount > 1 then
				self.CatmullRomController.EntityList[NodeIndex].LastGuideBeamRenderTimestamp = CTime
				render.StartBeam(2)
				render.AddBeam(self.CatmullRomController.PointsList[NodeIndex], 5, 10 + CTime, self.Color)
				render.AddBeam(self.CatmullRomController.PointsList[NodeIndex + 1], 5, CTime, self.Color)
				render.EndBeam()
			end
		elseif NodeIndex == self.CatmullRomController.CLEntityListCount then
			if self.CatmullRomController.CLEntityListCount > 1 then
				self.CatmullRomController.EntityList[self.CatmullRomController.CLEntityListCount].LastGuideBeamRenderTimestamp = CTime
				render.StartBeam(2)
				render.AddBeam(self.CatmullRomController.PointsList[self.CatmullRomController.CLEntityListCount - 1], 5, 10 + CTime, self.Color)
				render.AddBeam(self.CatmullRomController.PointsList[self.CatmullRomController.CLEntityListCount], 5, CTime, self.Color)
				render.EndBeam()
			end

			self.CatmullRomController.EntityList[NodeIndex].LastGuideBeamRenderTimestamp = CTime
			render.StartBeam(self.CatmullRomController.STEPS + 2)
				ok, err = pcall(self.RenderSubBeams, self, CTime, NodeIndex)
			render.EndBeam()

		else
			self.CatmullRomController.EntityList[NodeIndex].LastGuideBeamRenderTimestamp = CTime
			render.StartBeam(self.CatmullRomController.STEPS + 2)
				ok, err = pcall(self.RenderSubBeams, self, CTime, NodeIndex)
			render.EndBeam()
		end
	end
end

function ENT:GetGuideCamPosAng(pos1, pos2, pos3, pos4)
	if self:GetNWBool("IsMasterController") then
		self:CalcPerc() -- Can't be done in the parameter call or a side effect doesn't manifest properly
		
		return self.CatmullRomController:Point(), self.CatmullRomController:Angle()
	end
end

function ENT:RenderBeams()
	local CTime = CurTime()
	render.AddBeam(self.CatmullRomController.PointsList[2], 10, CTime, self.Color)

	for i = 1, #self.CatmullRomController.Spline do
		render.AddBeam(self.CatmullRomController.Spline[i], 10, CTime, self.Color)
	end
end

function ENT:RenderSubBeams(CTime, NodeIndex)

	local base = (NodeIndex - 2) * self.CatmullRomController.STEPS	

	render.AddBeam(self.CatmullRomController.PointsList[NodeIndex], 5, 0 - CTime, self.Color)
	//for i = 1, self.CatmullRomController.STEPS do
	//	render.AddBeam(self.CatmullRomController.Spline[base + i], 10, i - CTime, self.Color)
	//end

	local startPoint = self.CatmullRomController.Spline[base + 0]
	local endPoint = self.CatmullRomController.Spline[base + self.CatmullRomController.STEPS]
	

	render.AddBeam(self.CatmullRomController.Spline[base + 0], 5, 0 - CTime, self.Color)
	render.AddBeam(self.CatmullRomController.Spline[base + self.CatmullRomController.STEPS], 5, startPoint:Distance(endPoint) / 10 - CTime, self.Color)
	
	render.AddBeam(self.CatmullRomController.PointsList[NodeIndex + 1], 5, self.CatmullRomController.STEPS + 1 - CTime, self.Color)
end

function ENT:RemoveGuideGhost()
	if self.GuideCameraGhost and self.GuideCameraGhost:IsValid() then
		self.GuideCameraGhost:Remove()
		
		self.GuideCameraGhost = nil
	end
end
